-- $Id: $
-- File name:   tb_MEMORY_CONTROLLER.vhd
-- Created:     4/14/2011
-- Author:      Marcelo Leone
-- Lab Section: 337-06
-- Version:     1.0  Initial Test Bench

library ieee;
use ieee.std_logic_1164.all;
use IEEE.std_logic_textio.all;
use std.textio.all;
library ECE337_IP;
use ECE337_IP.all;

entity tb_MEMORY_CONTROLLER is
generic (Period : Time := 10.416667 ns);
end tb_MEMORY_CONTROLLER;

architecture TEST of tb_MEMORY_CONTROLLER is

  function INT_TO_STD_LOGIC( X: INTEGER; NumBits: INTEGER )
     return STD_LOGIC_VECTOR is
    variable RES : STD_LOGIC_VECTOR(NumBits-1 downto 0);
    variable tmp : INTEGER;
  begin
    tmp := X;
    for i in 0 to NumBits-1 loop
      if (tmp mod 2)=1 then
        res(i) := '1';
      else
        res(i) := '0';
      end if;
      tmp := tmp/2;
    end loop;
    return res;
  end;

  component MEMORY_CONTROLLER
    PORT(
         CLK : in std_logic;
         RST : in std_logic;
         --SYNC : in std_logic;
         EN : out std_logic;
         ERR : out std_logic;
         CRIT : out std_logic;
         REQ_Tx_DATA : out std_logic;
         Tx_DATA_STB : in std_logic;
         NEW_Rx_DATA : out std_logic;
         Rx_DATA_STB : in std_logic;
         ADDR : out std_logic_vector(11 downto 0);
         DATA_in : in std_logic_vector(7 downto 0);
         DATA_out : out std_logic_vector(7 downto 0);
         RW : out std_logic;
         RE : out std_logic;
         WE : out std_logic;
         BUSY : out std_logic;
         OWN_MEM : out std_logic;
         OUTDATA : out std_logic_vector(15 downto 0);
         OUTSTRB : out std_logic;
         OUTREQ : in std_logic;
         I0DATA : in std_logic_vector(15 downto 0);
         I0DRW : in std_logic;
         I0DRB : in std_logic;
         I0STRB : out std_logic;
         I1DATA : in std_logic_vector(15 downto 0);
         I1DRW : in std_logic;
         I1DRB : in std_logic;
         I1STRB : out std_logic
    );
  end component;  

  -- The declaration for the on-chip scalable sram model
  component scalable_off_chip_sram is
    generic (
            -- Memory Model parameters
            ADDR_SIZE_BITS  : natural  := 12;    -- Address bus size in bits/pins with addresses corresponding to 
                                                -- the starting word of the accesss
            WORD_SIZE_BYTES  : natural  := 1;      -- Word size of the memory in bytes
            DATA_SIZE_WORDS  : natural  := 1;      -- Data bus size in "words"
            READ_DELAY      : time    := 10 ns;  -- Delay/latency per read access (total time between start of supplying address and when the data read from memory appears on the r_data port)
                                                -- Keep the 10 ns delay for on-chip SRAM
            WRITE_DELAY      : time    := 10 ns    -- Delay/latency per write access (total time between start of supplying address and when the w_data value is written into memory)
                                                -- Keep the 10 ns delay for on-chip SRAM
          );
  port   (
          -- Test bench control signals
          mem_clr        : in  boolean;
          mem_init      : in  boolean;
          mem_dump      : in  boolean;
          verbose        : in  boolean;
          init_filename  : in   string;
          dump_filename  : in   string;
          start_address  : in  natural;
          last_address  : in  natural;
          
          -- Memory interface signals
          r_enable  : in    std_logic;
          w_enable  : in    std_logic;
          addr      : in    std_logic_vector((addr_size_bits - 1) downto 0);
          data      : inout  std_logic_vector(((data_size_words * word_size_bytes * 8) - 1) downto 0)
        );
  end component scalable_off_chip_sram;

-- Insert signals Declarations here
  signal CLK : std_logic;
  signal RST : std_logic;
  --signal SYNC : std_logic;
  signal EN : std_logic;
  signal ERR : std_logic;
  signal CRIT : std_logic;
  signal REQ_Tx_DATA : std_logic;
  signal Tx_DATA_STB : std_logic;
  signal NEW_Rx_DATA : std_logic;
  signal Rx_DATA_STB : std_logic;
  signal ADDR : std_logic_vector(11 downto 0);
  signal DATA_in : std_logic_vector(7 downto 0);
  signal DATA_out : std_logic_vector(7 downto 0);
  signal RW : std_logic;
  signal RE : std_logic;
  signal WE : std_logic;
  signal BUSY : std_logic;
  signal OWN_MEM : std_logic;
  signal OUTDATA : std_logic_vector(15 downto 0);
  signal OUTSTRB : std_logic;
  signal OUTREQ : std_logic;
  signal I0DATA : std_logic_vector(15 downto 0);
  signal I0DRW : std_logic;
  signal I0DRB : std_logic;
  signal I0STRB : std_logic;
  signal I1DATA : std_logic_vector(15 downto 0);
  signal I1DRW : std_logic;
  signal I1DRB : std_logic;
  signal I1STRB : std_logic;
  
  -- SRAM signals
  signal tb_data : std_logic_vector(7 downto 0);
  signal tb_mem_clr : boolean;
  signal tb_mem_init : boolean;
  signal tb_mem_dump : boolean;
  signal tb_verbose : boolean;
  signal tb_init_filename : string(23 downto 1);
  signal tb_dump_filename : string(23 downto 1);
  signal tb_start_address : natural;
  signal tb_last_address : natural;

-- signal <name> : <type>;

begin

CLKGEN: process
  variable CLK_tmp: std_logic := '0';
begin
  CLK_tmp := not CLK_tmp;
  CLK <= CLK_tmp;
  wait for Period/2;
end process;

  DUT: MEMORY_CONTROLLER port map(
                CLK => CLK,
                RST => RST,
                --SYNC => SYNC,
                EN => EN,
                ERR => ERR,
                CRIT => CRIT,
                REQ_Tx_DATA => REQ_Tx_DATA,
                Tx_DATA_STB => Tx_DATA_STB,
                NEW_Rx_DATA => NEW_Rx_DATA,
                Rx_DATA_STB => Rx_DATA_STB,
                ADDR => ADDR,
                DATA_in => DATA_in,
                DATA_out => DATA_out,
                RW => RW,
                RE => RE,
                WE => WE,
                BUSY => BUSY,
                OWN_MEM => OWN_MEM,
                OUTDATA => OUTDATA,
                OUTSTRB => OUTSTRB,
                OUTREQ => OUTREQ,
                I0DATA => I0DATA,
                I0DRW => I0DRW,
                I0DRB => I0DRB,
                I0STRB => I0STRB,
                I1DATA => I1DATA,
                I1DRW => I1DRW,
                I1DRB => I1DRB,
                I1STRB => I1STRB
                );
                
  -- An example of how to map an instance of the on-chip scalable sram model (Taken from my test bench)
  Memory: scalable_off_chip_sram
    port map  (
                -- Test bench control signals
                mem_clr        => tb_mem_clr,
                mem_init      => tb_mem_init,
                mem_dump      => tb_mem_dump,
                verbose        => tb_verbose,
                init_filename  => tb_init_filename,
                dump_filename  => tb_dump_filename,
                start_address  => tb_start_address,
                last_address  => tb_last_address,
                
                -- Memory interface signals
                r_enable  => RE,
                w_enable  => WE,
                addr      => ADDR,
                data      => tb_data
              );

-- Example of how to connect up to the bidirectional data bus
  IO_DATA: process ( RW, tb_data, DATA_out )
  begin
    if (RW = '1') then
      -- Read mode -> the data pins should connect to the r_data bus & the other bus should float
      DATA_in  <= tb_data;
      tb_data  <= (others=>'Z');
    elsif(RW = '0') then
      -- Write mode -> the data pins should connect to the w_data bus & the other bus should float
      DATA_in  <= (others=>'Z');
      tb_data  <= DATA_out;
    else
      -- Disconnect both busses
      DATA_in  <= (others=>'Z');
      tb_data       <= (others=>'Z');
    end if;
  end process IO_DATA;


process

  begin

-- Insert TEST BENCH Code Here

    RST <= '0';
    --SYNC <= '0';
    Tx_DATA_STB <= '0';
    Rx_DATA_STB <= '0';
    --DATA_in <= x"00";
    OUTREQ <= '0';
    I0DATA <= x"0000";
    I0DRW <= '0';
    I0DRB <= '0';
    I1DATA <= x"0000";
    I1DRW <= '0';
    I1DRB <= '0';
    
    -- Example of how to init the memory contents from a file
    tb_mem_init        <= TRUE;
    tb_init_filename   <= "test_io/mem_init_00.txt";
    wait for Period;
    tb_mem_init        <= FALSE;
    
    -- Example of how to dump the memory contents to a file
    --tb_mem_dump        <= TRUE;
    --tb_dump_filename  <=  "test_io/mem_dump_00.txt";
    --tb_start_address  <= 0; -- Can be any address 
    --tb_last_address    <= 383; -- Can be any address larger than the start_address
    --wait for Period; -- Can be as long or as short as you like, as long as it is longer than 1 simulation time-step
    --tb_mem_dump        <= FALSE;
    
    RST <= '1';
    
    wait for Period*2;
    
    OUTREQ <= '1'; 
    wait for Period*12;
    OUTREQ <= '0';
    wait for Period*20;
    
    OUTREQ <= '1';   
    wait for Period*12;
    OUTREQ <= '0';
    wait for Period*20;
    
    OUTREQ <= '1';   
    wait for Period*12;
    OUTREQ <= '0';
    wait for Period*20;
    -- ~0.8 us
    report " -- COMMAND OUT DONE -- ";
    
    I0DATA <= x"C0C1";
    OUTREQ <= '1';
    I0DRW <= '1';
    wait for Period*12;
    OUTREQ <= '0';
    wait for Period*6;
    I0DRW <= '0';
    wait for Period*14;
    
    OUTREQ <= '1';   
    wait for Period*12;
    OUTREQ <= '0';
    wait for Period*20;
    
    I0DATA <= x"C2C3";
    OUTREQ <= '1';
    I0DRW <= '1';
    wait for Period*12;
    OUTREQ <= '0';
    wait for Period*6;
    I0DRW <= '0';
    wait for Period*14;
    
    OUTREQ <= '1';   
    wait for Period*12;
    OUTREQ <= '0';
    wait for Period*20;
    
    I0DATA <= x"C3C4";
    OUTREQ <= '1';
    I0DRB <= '1';
    wait for Period*12;
    OUTREQ <= '0';
    wait for Period*6;
    I0DRB <= '0';
    wait for Period*14;
    
    OUTREQ <= '1';   
    wait for Period*12;
    OUTREQ <= '0';
    wait for Period*20;
    
    I0DATA <= x"D000";
    OUTREQ <= '1';
    I0DRW <= '1';
    wait for Period*12;
    OUTREQ <= '0';
    wait for Period*6;
    I0DRW <= '0';
    wait for Period*14;
    
    OUTREQ <= '1';   
    wait for Period*12;
    OUTREQ <= '0';
    wait for Period*20;
    
    I0DATA <= x"D001";
    OUTREQ <= '1';
    I0DRW <= '1';
    wait for Period*12;
    OUTREQ <= '0';
    wait for Period*6;
    I0DRW <= '0';
    wait for Period*14;
    
    OUTREQ <= '1';   
    wait for Period*12;
    OUTREQ <= '0';
    wait for Period*20;
    
    I0DATA <= x"D002";
    OUTREQ <= '1';
    I0DRW <= '1';
    wait for Period*12;
    OUTREQ <= '0';
    wait for Period*6;
    I0DRW <= '0';
    wait for Period*14;
    
    OUTREQ <= '1';   
    wait for Period*12;
    OUTREQ <= '0';
    wait for Period*20;
    
    I0DATA <= x"D003";
    OUTREQ <= '1';
    I0DRW <= '1';
    wait for Period*12;
    OUTREQ <= '0';
    wait for Period*6;
    I0DRW <= '0';
    wait for Period*14;
    
    OUTREQ <= '1';   
    wait for Period*12;
    OUTREQ <= '0';
    wait for Period*20;
    
    I0DATA <= x"D004";
    OUTREQ <= '1';
    I0DRW <= '1';
    wait for Period*12;
    OUTREQ <= '0';
    wait for Period*6;
    I0DRW <= '0';
    wait for Period*14;
    
    OUTREQ <= '1';   
    wait for Period*12;
    OUTREQ <= '0';
    wait for Period*20;
    -- ~6.2 us
    report " -- FIRST OUTPUT DONE -- ";   
    
    I0DATA <= x"D005";
    OUTREQ <= '1';
    I0DRW <= '1';
    wait for Period*12;
    OUTREQ <= '0';
    wait for Period*6;
    I0DRW <= '0';
    wait for Period*14;
    
    OUTREQ <= '1';   
    wait for Period*12;
    OUTREQ <= '0';
    wait for Period*20;
    
    OUTREQ <= '1';   
    I0DATA <= x"D006";
    OUTREQ <= '1';
    I0DRW <= '1';
    wait for Period*12;
    OUTREQ <= '0';
    wait for Period*6;
    I0DRW <= '0';
    wait for Period*14;
    
    OUTREQ <= '1';   
    wait for Period*12;
    OUTREQ <= '0';
    wait for Period*20;
    
    I0DATA <= x"D007";
    OUTREQ <= '1';
    I0DRW <= '1';
    wait for Period*12;
    OUTREQ <= '0';
    wait for Period*6;
    I0DRW <= '0';
    wait for Period*14;
    
    I0DATA <= x"D008";
    OUTREQ <= '1';
    I0DRW <= '1';
    wait for Period*12;
    OUTREQ <= '0';
    wait for Period*6;
    I0DRW <= '0';
    wait for Period*14;
    
    OUTREQ <= '1';   
    wait for Period*12;
    OUTREQ <= '0';
    wait for Period*20;
    
    I0DATA <= x"D009";
    OUTREQ <= '1';
    I0DRW <= '1';
    wait for Period*12;
    OUTREQ <= '0';
    wait for Period*6;
    I0DRW <= '0';
    wait for Period*14;
    
    OUTREQ <= '1';   
    wait for Period*12;
    OUTREQ <= '0';
    wait for Period*20;
    
    I0DATA <= x"D010";
    OUTREQ <= '1';
    I0DRW <= '1';
    wait for Period*12;
    OUTREQ <= '0';
    wait for Period*6;
    I0DRW <= '0';
    wait for Period*14;
    
    OUTREQ <= '1';   
    wait for Period*12;
    OUTREQ <= '0';
    wait for Period*20;
    
    I0DATA <= x"D011";
    OUTREQ <= '1';
    I0DRW <= '1';
    wait for Period*12;
    OUTREQ <= '0';
    wait for Period*6;
    I0DRW <= '0';
    wait for Period*14;
    
    OUTREQ <= '1';   
    wait for Period*12;
    OUTREQ <= '0';
    wait for Period*20;
    
    I0DATA <= x"D012";
    OUTREQ <= '1';
    I0DRW <= '1';
    wait for Period*12;
    OUTREQ <= '0';
    wait for Period*6;
    I0DRW <= '0';
    wait for Period*14;
    
    OUTREQ <= '1';   
    wait for Period*12;
    OUTREQ <= '0';
    wait for Period*20;
    
    I0DATA <= x"D013";
    OUTREQ <= '1';
    I0DRW <= '1';
    wait for Period*12;
    OUTREQ <= '0';
    wait for Period*6;
    I0DRW <= '0';
    wait for Period*14;
    
    OUTREQ <= '1';   
    wait for Period*12;
    OUTREQ <= '0';
    wait for Period*20;
    
    I0DATA <= x"D014";
    OUTREQ <= '1';
    I0DRW <= '1';
    wait for Period*12;
    OUTREQ <= '0';
    wait for Period*6;
    I0DRW <= '0';
    wait for Period*14;
    
    OUTREQ <= '1';   
    wait for Period*12;
    OUTREQ <= '0';
    wait for Period*20;
    
    I0DATA <= x"D015";
    OUTREQ <= '1';
    I0DRW <= '1';
    wait for Period*12;
    OUTREQ <= '0';
    wait for Period*6;
    I0DRW <= '0';
    wait for Period*14;
    
    OUTREQ <= '1';   
    wait for Period*12;
    OUTREQ <= '0';
    wait for Period*20;
    
    I0DATA <= x"D016";
    OUTREQ <= '1';
    I0DRW <= '1';
    wait for Period*12;
    OUTREQ <= '0';
    wait for Period*6;
    I0DRW <= '0';
    wait for Period*14;
    
    OUTREQ <= '1';   
    wait for Period*12;
    OUTREQ <= '0';
    wait for Period*20;
    
    I0DATA <= x"D017";
    OUTREQ <= '1';
    I0DRW <= '1';
    wait for Period*12;
    OUTREQ <= '0';
    wait for Period*6;
    I0DRW <= '0';
    wait for Period*14;
    -- ~14.2 us
    report " -- SECOND OUTPUT DONE -- ";
    
    wait for Period*32;
    
    I0DATA <= x"D018";
    I0DRW <= '1';
    wait for Period*6;
    I0DRW <= '0';
    wait for Period*58;
    
    I0DATA <= x"D019";
    I0DRW <= '1';
    wait for Period*6;
    I0DRW <= '0';
    wait for Period*58;
    
    I0DATA <= x"D020";
    I0DRW <= '1';
    wait for Period*6;
    I0DRW <= '0';
    wait for Period*58;
    
    I0DATA <= x"D021";
    I0DRW <= '1';
    wait for Period*6;
    I0DRW <= '0';
    wait for Period*58;
    
    I0DATA <= x"D022";
    I0DRW <= '1';
    wait for Period*6;
    I0DRW <= '0';
    wait for Period*58;
    
    I0DATA <= x"D023";
    I0DRW <= '1';
    wait for Period*6;
    I0DRW <= '0';
    wait for Period*58;
    
    tb_mem_dump        <= TRUE;
    tb_dump_filename  <=  "test_io/mem_dump_00.txt";
    tb_start_address  <= 0; -- Can be any address 
    tb_last_address    <= 383; -- Can be any address larger than the start_address
    wait for Period; -- Can be as long or as short as you like, as long as it is longer than 1 simulation time-step
    tb_mem_dump        <= FALSE;
    
    wait;

  end process;
  
end TEST;